# -*- coding:utf-8 -*-
#发布回滚类
import yaml
from server.argparse_operation import getParameters
from server.svn_operation import svnCheckout
from server.yaml_operation import getDict
from server.ansible_operation import AnsibleApi
from server.git_operation import GitRepository
from server.svn_operation import *
import os
import sys
import datetime

class PostCode:
    def __init__(self,parameter):
        self.curr_time = datetime.datetime.now()
        self.now_time = datetime.datetime.strftime(self.curr_time,'%Y%m%d%H%M%S')
        self.parameter_config = parameter.config

    #功能块：加快ansible执行方法
    def ansible_shll(self,host,module,args):
        run_ansible = AnsibleApi()
        tasks_list = []
        tasks_list.append(dict(action=dict(module=module, args=args)))
        run_ansible.runansible(host,tasks_list)

    #功能块：拉取代码前后执行shell
    def pullTheShellBefore(self,yaml_config,check_out_the_action):
        print('--------------拉取代码%s执行shell--------------'%check_out_the_action)
        pull_the_shell_before = yaml_config['Ansible'][check_out_the_action]
        if check_out_the_action == 'before_code_replacement' or check_out_the_action == 'after_code_replacement':
            command_host = yaml_config['Ansible']['group']
        elif check_out_the_action == 'check_out _before' or check_out_the_action == 'after_check_out':
            command_host = '127.0.0.1'
        if pull_the_shell_before != None:
            for command_statement in pull_the_shell_before:
                tasks_list = []
                ansible_module = command_statement['module']
                ansible_command = command_statement['args']
                tasks_list.append(dict(action=dict(module=ansible_module, args=ansible_command)))
                run_ansible = AnsibleApi()
                run_ansible.runansible(command_host,tasks_list)
        else:
            print('当前无指令操作，自动跳过。')
        print('+++++++++++++++++++执行完成++++++++++++++++++++\n\n' + '@' * 200)

    #功能块：svn拉取代码
    def checkoutTheCode(self,yaml_config,commit_num=None):
        print('------------------检出代码中-------------------')
        project_name = str(os.path.basename(yaml_config['Svn']['SvnUrl']))
        local_path = yaml_config['Svn']['SvnPath'] + '/' + project_name
        username = yaml_config['Svn']['SvnUser']
        password = yaml_config['Svn']['SvnPass']
        svn_url = yaml_config['Svn']['SvnUrl']
        if commit_num == None:
            svn_checkout = svnCheckout(local_path=local_path,username=username,password=password,url=svn_url)
            print(svn_checkout)
            print('检出svn代码....')
        else:
            svn_commit = svnCommit(local_path=local_path,username=username,password=password,version=commit_num)
            print(svn_commit)
            print('回滚svn version：%s'%commit_num)
        print('+++++++++++++++++++检出完成++++++++++++++++++++\n\n' + '@' * 200)

    #功能块：git拉取代码
    def pullTheCode(self,yaml_config,commit_num=None):
        print('------------------检出代码中-------------------')
        project_name = str(os.path.basename(yaml_config['Git']['GitUrl'])).split('.')[0]
        local_path = yaml_config['Git']['GitPath'] + '/' + project_name
        git_url = yaml_config['Git']['GitUrl']
        git_branch = yaml_config['Git']['GitBranch']
        repo = GitRepository(local_path=local_path,repo_url=git_url,branch=git_branch)
        if commit_num == None:
            repo.change_to_branch(git_branch)
            repo.pull()
            print('检出分支：%s'%git_branch)
        else:
            repo.pull()
            repo.change_to_commit(branch=git_branch,commit=commit_num)
            print('回滚commit：%s'%commit_num)

        print('+++++++++++++++++++检出完成++++++++++++++++++++\n\n' + '@' * 200)

    #功能块：ansible传输svn代码文件
    def transferSvnFiles(self,yaml_config):
        print('------------------代码传送至目标服务器项目目录下-------------------')
        project_name = str(os.path.basename(yaml_config['Svn']['SvnUrl']))
        svn_code_path = yaml_config['Svn']['SvnPath'] + '/' + project_name
        code_version_path = yaml_config['Web']['version_retain_path']
        if yaml_config['Web']['fast_deploy']:
            print('正在执行简易发布')
            web_back_path = yaml_config['Web']['version_retain_path'] + '/' + project_name
        else:
            print('正在执行复杂发布')
            web_back_path = yaml_config['Web']['version_retain_path'] + '/' + project_name + '_' + self.now_time
        web_group = yaml_config['Ansible']['group']
        exclude_file = yaml_config['Web']['exclude']
        mkdir_code_version="if [ ! -d '" + code_version_path + "' ];then mkdir -p " + code_version_path + ";fi"
        self.ansible_shll(web_group,'shell',mkdir_code_version)
        rsync_args = None
        rsync_args = "src=" + svn_code_path + "/ " + "dest=" + web_back_path  + " " + "delete=yes" + " " +  "compress=yes" + " " + "rsync_opts='"
        for file_name in exclude_file:
            rsync_args = rsync_args + "--exclude=" + file_name + " "
        rsync_args = rsync_args + "'"
        try:
            self.ansible_shll(web_group,'synchronize',rsync_args)
        except KeyError:
            print('报错：无法获取错误信息，在传输文件时同步模块异常，请检查模块。')
            sys.exit(1)
        print('+++++++++++++++++++传送结束++++++++++++++++++++\n\n' + '@' * 200)
        print("src=%s,dest=%s"%(svn_code_path,web_back_path))
        return web_back_path

    #功能块：ansible传输git代码文件
    def transferFiles(self,yaml_config):
        print('------------------代码传送至目标服务器项目目录下-------------------')
        project_name = str(os.path.basename(yaml_config['Git']['GitUrl'])).split('.')[0]
        git_code_path = yaml_config['Git']['GitPath'] + '/' + project_name
        code_version_path = yaml_config['Web']['version_retain_path']
        #判断是否简单发布，简单发布存在缺陷，无法回滚上一版本，只能按照commit回滚。
        if yaml_config['Web']['fast_deploy']:
            print('正在执行简易发布')
            web_back_path = yaml_config['Web']['version_retain_path'] + '/' + project_name
        else:
            print('正在执行复杂发布')
            web_back_path = yaml_config['Web']['version_retain_path'] + '/' + project_name + '_' + self.now_time
        web_group = yaml_config['Ansible']['group']
        exclude_file = yaml_config['Web']['exclude']
        mkdir_code_version="if [ ! -d '" + code_version_path + "' ];then mkdir -p " + code_version_path + ";fi"
        self.ansible_shll(web_group,'shell',mkdir_code_version)
        rsync_args = None
        rsync_args = "src=" + git_code_path + "/ " + "dest=" + web_back_path  + " " + "delete=yes" + " " +  "compress=yes" + " " + "rsync_opts='"
        for file_name in exclude_file:
            rsync_args = rsync_args + "--exclude=" + file_name + " "
        rsync_args = rsync_args + "'"
        try:
            self.ansible_shll(web_group,'synchronize',rsync_args)
        except KeyError:
            print('报错：无法获取错误信息，在传输文件时同步模块异常，请检查模块。')
            sys.exit(1)
        print('+++++++++++++++++++传送结束++++++++++++++++++++\n\n' + '@' * 200)
        print("src=%s,dest=%s"%(git_code_path,web_back_path))
        return web_back_path

    #功能块：切换svn代码上线
    def replaceSvnTheOnline(self,yaml_config,project_name):
        print('------------------切换代码到线上环境-------------------')
        project_svn_name = str(os.path.basename(yaml_config['Svn']['SvnUrl']))
        project_path = yaml_config['Web']['webroot']
        web_back_path = yaml_config['Web']['version_retain_path']
        web_group = yaml_config['Ansible']['group']
        mkdir_shell = None
        mkdir_shell = "if [ ! -d '" + project_path + "' ];then mkdir -p " + project_path + ";fi"   #创建项目目录
        self.ansible_shll(host=web_group,module='shell',args=mkdir_shell)
        command_args = None
        #command_args = "/usr/bin/cp -raf " + version_path + "/" + project_name + "/*" + " " + project_path   #切换最新代码到线上
        command_args = "/usr/bin/cp -raf " + project_name + "/*" + " " + project_path
        self.ansible_shll(host=web_group,module='shell',args=command_args)
        keep_version = yaml_config['Web']['keep_version']
        keep_version_command = "for i in $(/usr/bin/ls -rt " + web_back_path + '|grep ' + project_svn_name+ '_' + ' | sort -rn ' +' | tail -n +' + str(int(keep_version) + 1) + ");do rm -rf " + web_back_path + "/$i ; done"
        self.ansible_shll(host=web_group,module='shell',args=keep_version_command)
        print('+++++++++++++++++++切换结束++++++++++++++++++++')

    #功能块：切换git代码上线
    def replaceTheOnline(self,yaml_config,project_name):
        print('------------------切换代码到线上环境-------------------')
        project_git_name = str(os.path.basename(yaml_config['Git']['GitUrl'])).split('.')[0]  #获取项目名称
        #version_path = yaml_config['Web']['version_retain_path']
        project_path = yaml_config['Web']['webroot']
        web_back_path = yaml_config['Web']['version_retain_path']
        web_group = yaml_config['Ansible']['group']
        mkdir_shell = None
        mkdir_shell = "if [ ! -d '" + project_path + "' ];then mkdir -p " + project_path + ";fi"   #创建项目目录
        self.ansible_shll(host=web_group,module='shell',args=mkdir_shell)
        command_args = None
        #command_args = "/usr/bin/cp -raf " + version_path + "/" + project_name + "/*" + " " + project_path   #切换最新代码到线上
        command_args = "/usr/bin/cp -raf " + project_name + "/*" + " " + project_path
        self.ansible_shll(host=web_group,module='shell',args=command_args)
        keep_version = yaml_config['Web']['keep_version']
        keep_version_command = "for i in $(/usr/bin/ls -rt " + web_back_path + '|grep ' + project_git_name+ '_' + ' | sort -rn ' +' | tail -n +' + str(int(keep_version) + 1) + ");do rm -rf " + web_back_path + "/$i ; done"
        self.ansible_shll(host=web_group,module='shell',args=keep_version_command)
        print('+++++++++++++++++++切换结束++++++++++++++++++++')
        
    #功能块：切换上一个版本svn代码上线
    def svnSwitchVersion(self,yaml_config):
        print('------------------切换上一版本代码到线上环境-------------------')
        project_svn_name = str(os.path.basename(yaml_config['Svn']['SvnUrl']))
        project_path = yaml_config['Web']['webroot']
        web_back_path = yaml_config['Web']['version_retain_path']
        web_group = yaml_config['Ansible']['group']
        select_version_command = '/bin/bash -c \'if [ ! -n "$(/usr/bin/ls -rt ' + web_back_path + '| grep ' + project_svn_name + '| head -n 1)" ]; then echo "服务版本：空";exit 1 ;fi\''
        self.ansible_shll(host=web_group,module='shell',args=select_version_command)
        switch_version_command = '/usr/bin/cp -raf ' + web_back_path + '/$(/usr/bin/ls -rt ' + web_back_path + '| grep ' + project_svn_name + '_' + ' | sort -rn ' +'| head -n 2 | tail -n 1)/* ' +  project_path
        self.ansible_shll(host=web_group,module='shell',args=switch_version_command)
        print('+++++++++++++++++++切换结束++++++++++++++++++++')

    #功能块：切换上一个版本git代码上线
    def switchVersion(self,yaml_config):
        print('------------------切换上一版本代码到线上环境-------------------')
        project_git_name = str(os.path.basename(yaml_config['Git']['GitUrl'])).split('.')[0]  #获取项目名称
        project_path = yaml_config['Web']['webroot']
        web_back_path = yaml_config['Web']['version_retain_path']
        web_group = yaml_config['Ansible']['group']
        select_version_command = '/bin/bash -c \'if [ ! -n "$(/usr/bin/ls -rt ' + web_back_path + '| grep ' + project_git_name + '| head -n 1)" ]; then echo "服务版本：空";exit 1 ;fi\''
        self.ansible_shll(host=web_group,module='shell',args=select_version_command)
        switch_version_command = '/usr/bin/cp -raf ' + web_back_path + '/$(/usr/bin/ls -rt ' + web_back_path + '| grep ' + project_git_name + '_' + ' | sort -rn ' +'| head -n 2 | tail -n 1)/* ' +  project_path
        self.ansible_shll(host=web_group,module='shell',args=switch_version_command)
        print('+++++++++++++++++++切换结束++++++++++++++++++++')


    #主任务：发布逻辑部分
    def deployCode(self):
        if self.parameter_config == None:
            print('错误：参数为空，执行run.py --help查询所需参数')
            sys.exit('异常退出程序')
        yaml_config = getDict('config/' + str(self.parameter_config)) #获取yml配置文件信息
        if yaml_config.__contains__('Git'):
            self.pullTheShellBefore(yaml_config,check_out_the_action='check_out _before')   #拉取前执行shell
            self.pullTheCode(yaml_config)  #拉取代码
            self.pullTheShellBefore(yaml_config,check_out_the_action='after_check_out')     #拉取后执行shell
            project_name_time = self.transferFiles(yaml_config=yaml_config)   #传送代码到服务器
            self.pullTheShellBefore(yaml_config=yaml_config,check_out_the_action='before_code_replacement')  #代码替换前执行shell
            self.replaceTheOnline(yaml_config=yaml_config,project_name=project_name_time)    #替换代码上线
            self.pullTheShellBefore(yaml_config,check_out_the_action='after_code_replacement')         #代码替换后执行shell
        elif yaml_config.__contains__('Svn'):
            self.pullTheShellBefore(yaml_config,check_out_the_action='check_out _before')   #拉取前执行shell
            self.checkoutTheCode(yaml_config) #拉取代码
            self.pullTheShellBefore(yaml_config,check_out_the_action='after_check_out')     #拉取后执行shell
            project_name_time = self.transferSvnFiles(yaml_config=yaml_config)   #传送代码到服务器
            self.pullTheShellBefore(yaml_config=yaml_config,check_out_the_action='before_code_replacement')  #代码替换前执行shell
            self.replaceSvnTheOnline(yaml_config=yaml_config,project_name=project_name_time)    #替换代码上线
            self.pullTheShellBefore(yaml_config,check_out_the_action='after_code_replacement')         #代码替换后执行shell

    #主任务：版本号回滚逻辑部分
    def rollbackCode(self,commit_num):
        if self.parameter_config == None:
            print('错误：参数为空，执行run.py --help查询所需参数')
            sys.exit('异常退出程序')
        yaml_config = getDict('config/' + str(self.parameter_config)) #获取yml配置文件信息
        if yaml_config.__contains__('Git'):
            self.pullTheShellBefore(yaml_config,check_out_the_action='check_out _before')   #拉取前执行shell
            self.pullTheCode(yaml_config,commit_num=commit_num)  #拉取代码
            self.pullTheShellBefore(yaml_config,check_out_the_action='after_check_out')     #拉取后执行shell
            project_name_tiem = self.transferFiles(yaml_config=yaml_config)   #传送代码到服务器
            self.pullTheShellBefore(yaml_config=yaml_config,check_out_the_action='before_code_replacement')  #代码替换前执行shell
            self.replaceTheOnline(yaml_config=yaml_config,project_name=project_name_tiem)    #替换代码上线
            self.pullTheShellBefore(yaml_config,check_out_the_action='after_code_replacement')         #代码替换后执行shell
        elif yaml_config.__contains__('Svn'):
            self.pullTheShellBefore(yaml_config,check_out_the_action='check_out _before')   #拉取前执行shell
            self.checkoutTheCode(yaml_config,commit_num=commit_num)  #拉取代码
            self.pullTheShellBefore(yaml_config,check_out_the_action='after_check_out')     #拉取后执行shell
            project_name_tiem = self.transferSvnFiles(yaml_config=yaml_config)   #传送代码到服务器
            self.pullTheShellBefore(yaml_config=yaml_config,check_out_the_action='before_code_replacement')  #代码替换前执行shell
            self.replaceSvnTheOnline(yaml_config=yaml_config,project_name=project_name_tiem)    #替换代码上线
            self.pullTheShellBefore(yaml_config,check_out_the_action='after_code_replacement')         #代码替换后执行shell

    #主任务：回滚到上一个版本
    def lastVersionCode(self):
        if self.parameter_config == None:
            print('错误：参数为空，执行run.py --help查询所需参数')
            sys.exit('异常退出程序')
        yaml_config = getDict('config/' + str(self.parameter_config))
        if yaml_config.__contains__('Git'):
            self.pullTheShellBefore(yaml_config=yaml_config,check_out_the_action='before_code_replacement')  #代码替换前执行shell
            self.switchVersion(yaml_config=yaml_config)           #切换上一个版本
            self.pullTheShellBefore(yaml_config,check_out_the_action='after_code_replacement')         #代码替换后执行shell
        elif yaml_config.__contains__('Svn'):
            self.pullTheShellBefore(yaml_config=yaml_config,check_out_the_action='before_code_replacement')  #代码替换前执行shell
            self.svnSwitchVersion(yaml_config=yaml_config)           #切换上一个版本
            self.pullTheShellBefore(yaml_config,check_out_the_action='after_code_replacement')         #代码替换后执行shell